package thread;

import java.util.PriorityQueue;
import java.util.Timer;
import java.util.TimerTask;

/*⼀个带优先级队列(不要使⽤ PriorityBlockingQueue, 容易死锁!)
• 队列中的每个元素是⼀个 Task 对象.
• Task 中带有⼀个时间属性, 队⾸元素就是即将要执⾏的任务
• 同时有⼀个 worker 线程⼀直扫描队⾸元素, 看队⾸元素是否需要执⾏ */

// 创建Timer类
class MyTimer {
    // 创建优先级队列,组织task任务
    private PriorityQueue<MyTask> priorityQueue = new PriorityQueue<>();
    // 创建锁对象
    private Object locked = new Object();

    // 创建带有任务和时间的schedule方法
    public void schedule(Runnable runnable, long after) {
        synchronized (locked) {
            // 构建myTask对象,将任务添加至队列中
            MyTask myTask = new MyTask(runnable, after);
            priorityQueue.offer(myTask);
            locked.notify();
        }
    }

    // 构造work线程,一直扫描队首元素,看是否能够执行这个任务
    public MyTimer() {
        Thread work = new Thread(() -> {
            while (true) {
                synchronized (locked) {
                    // 使用while来判断队列是否为空，不能使用if，因为有可能唤醒该线程的时候队列又为空了
                    while (priorityQueue.isEmpty()) {
                        try {
                            locked.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    // 创建Task对象，将队首元素取出，并获取系统时间戳
                    MyTask task = priorityQueue.peek();
                    long curTime = System.currentTimeMillis();
                    // 判断当前系统时间是否大于任务时间
                    if (curTime >= task.time) {
                        priorityQueue.poll();
                        // 执行该任务
                        task.runnable.run();
                    } else {
                        try {
                            // 用任务时间减去系统时间，来确定等待多久唤醒该线程
                            locked.wait(task.time - curTime);
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
        });
        work.start();
    }
}

// 创建Task类并实现Comparable接口
class MyTask implements Comparable<MyTask> {
    public Runnable runnable;
    public long time;

    // 初始化
    public MyTask(Runnable runnable, long delay) {
        this.runnable = runnable;
        this.time = System.currentTimeMillis() + delay;
    }

    // 通过重写comparTo进行优先级队列的元素排序
    @Override
    public int compareTo(MyTask o) {
        return (int) (this.time - o.time);
    }
}

public class test21 {
    public static void main1(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(5000);
            }
        }, 5000);
    }

    public static void main(String[] args) {
        MyTimer myTimer = new MyTimer();
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("5000");
            }
        }, 5000);
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("4000");
            }
        }, 4000);
        myTimer.schedule(new Runnable() {
            @Override
            public void run() {
                System.out.println("3000");
            }
        }, 3000);
    }
}
